---
title: Dependency Free Composability
description:
  Learn how to use Anchor's declare_program macro to interact with programs
  without additional dependencies.
---

The
[`declare_program!()`](https://github.com/coral-xyz/anchor/tree/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program)
macro simplifies the process of interacting with Anchor programs by generating
Rust modules (from a program's IDL) that can be used in both on-chain and
off-chain code. You can find an example program
[here](https://github.com/coral-xyz/anchor/tree/master/tests/declare-program).

The following modules are generated by the `declare_program!()` macro:

| Module                                                                                                                                                        | Description                                                                                              |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| [`cpi`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/cpi.rs)             | Helper functions for making cross-program invocations (CPIs) to the program from other on-chain programs |
| [`client`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/client.rs)       | Accounts and arguments required to build program instructions to add to client-side transactions         |
| [`account`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/accounts.rs)    | Account data types (program state) defined in the program                                                |
| [`program`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/program.rs)     | Program ID constant used to identify the program                                                         |
| [`constants`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/constants.rs) | Program constants defined in the program                                                                 |
| [`events`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/events.rs)       | Program events defined in the program                                                                    |
| [`types`](https://github.com/coral-xyz/anchor/blob/0e5285aecdf410fa0779b7cd09a47f235882c156/lang/attribute/program/src/declare_program/mods/types.rs)         | Program types defined in the program                                                                     |

## Examples

The following examples demonstrate how to use the `declare_program!()` macro in
two scenarios:

1. Making Cross Program Invocations (CPIs) from one program to another program
2. Building client-side transactions to invoke a program's instructions

Both examples show how the modules generated by the `declare_program!()` macro
simplify program interactions, whether you're writing on-chain or off-chain
code.

### On-chain CPI

To use the `declare_program!()` macro, you need the IDL file for the target
program. The IDL file must be placed in a directory named `/idls` in your
project. The `/idls` directory can be located at any level in your project
structure. For example, your project could have this layout:

<Files>
  <Folder name="idls" defaultOpen={true}>
    <File name="example.json" />
  </Folder>
  <Folder name="programs" defaultOpen={true}>
    <Folder name="example-cpi" defaultOpen={true}>
      <Folder name="src" defaultOpen={true}>
        <File name="lib.rs" />
      </Folder>
      <File name="Cargo.toml" />
    </Folder>
  </Folder>
</Files>

Below is the source code (`lib.rs`) for the target (callee) program that
generates the `example.json` IDL file shown above.

Using the program's IDL file, another program can use the `declare_program!()`
macro to generate a CPI module, enabling it to make CPIs to this program's
instructions.

<Tabs items={["Callee Program", "IDL"]}>

```rust tab="Callee Program"
use anchor_lang::prelude::*;

declare_id!("8HupNBr7SBhBLcBsLhbtes3tCarBm6Bvpqp5AfVjHuj8");

#[program]
pub mod example {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let counter = &ctx.accounts.counter;
        msg!("Counter account created! Current count: {}", counter.count);
        Ok(())
    }

    pub fn increment(ctx: Context<Increment>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        msg!("Previous counter: {}", counter.count);

        counter.count += 1;
        msg!("Counter incremented! Current count: {}", counter.count);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(mut)]
    pub payer: Signer<'info>,

    #[account(
        init,
        payer = payer,
        space = 8 + 8
    )]
    pub counter: Account<'info, Counter>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut)]
    pub counter: Account<'info, Counter>,
}

#[account]
pub struct Counter {
    pub count: u64,
}
```

```ts tab="IDL"
{
  "address": "8HupNBr7SBhBLcBsLhbtes3tCarBm6Bvpqp5AfVjHuj8",
  "metadata": {
    "name": "example",
    "version": "0.1.0",
    "spec": "0.1.0",
    "description": "Created with Anchor"
  },
  "instructions": [
    {
      "name": "increment",
      "discriminator": [
        11,
        18,
        104,
        9,
        104,
        174,
        59,
        33
      ],
      "accounts": [
        {
          "name": "counter",
          "writable": true
        }
      ],
      "args": []
    },
    {
      "name": "initialize",
      "discriminator": [
        175,
        175,
        109,
        31,
        13,
        152,
        155,
        237
      ],
      "accounts": [
        {
          "name": "payer",
          "writable": true,
          "signer": true
        },
        {
          "name": "counter",
          "writable": true,
          "signer": true
        },
        {
          "name": "system_program",
          "address": "11111111111111111111111111111111"
        }
      ],
      "args": []
    }
  ],
  "accounts": [
    {
      "name": "Counter",
      "discriminator": [
        255,
        176,
        4,
        245,
        188,
        253,
        124,
        25
      ]
    }
  ],
  "types": [
    {
      "name": "Counter",
      "type": {
        "kind": "struct",
        "fields": [
          {
            "name": "count",
            "type": "u64"
          }
        ]
      }
    }
  ]
}
```

</Tabs>

Below is the source code (`lib.rs`) for the caller program (example-cpi) that
uses the `declare_program!()` macro to generate a CPI module to invoke the
instructions defined in the callee program above.

<Tabs items={["Caller Program", "Test"]}>

```rust tab="Caller Program"
use anchor_lang::prelude::*;

declare_id!("GENmb1D59wqCKRwujq4PJ8461EccQ5srLHrXyXp4HMTH");

// [!code word:declare_program]
// [!code highlight:9]
declare_program!(example);
use example::{
    accounts::Counter,
    cpi::{
        self,
        accounts::{Increment, Initialize},
    },
    program::Example,
};

#[program]
pub mod example_cpi {

    use super::*;

    pub fn initialize_cpi(ctx: Context<InitializeCpi>) -> Result<()> {
        // Create CPI context for initialize
        let cpi_ctx = CpiContext::new(
            ctx.accounts.example_program.to_account_info(),
            Initialize {
                payer: ctx.accounts.payer.to_account_info(),
                counter: ctx.accounts.counter.to_account_info(),
                system_program: ctx.accounts.system_program.to_account_info(),
            },
        );

        // Invoke the initialize instruction
        cpi::initialize(cpi_ctx)?;
        Ok(())
    }

    pub fn increment_cpi(ctx: Context<IncrementCpi>) -> Result<()> {
        // Create CPI context for increment
        let cpi_ctx = CpiContext::new(
            ctx.accounts.example_program.to_account_info(),
            Increment {
                counter: ctx.accounts.counter.to_account_info(),
            },
        );

        // Invoke the increment instruction
        cpi::increment(cpi_ctx)?;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct InitializeCpi<'info> {
    #[account(mut)]
    pub payer: Signer<'info>,
    #[account(mut)]
    pub counter: Signer<'info>,
    pub system_program: Program<'info, System>,
    pub example_program: Program<'info, Example>,
}

#[derive(Accounts)]
pub struct IncrementCpi<'info> {
    #[account(mut)]
    pub counter: Account<'info, Counter>,
    pub example_program: Program<'info, Example>,
}
```

```ts tab="Test"
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { Example } from "../target/types/example";
import { ExampleCpi } from "../target/types/example_cpi";
import { Keypair } from "@solana/web3.js";

describe("example", () => {
  anchor.setProvider(anchor.AnchorProvider.env());

  const program = anchor.workspace.Example as Program<Example>;
  const cpiProgram = anchor.workspace.ExampleCpi as Program<ExampleCpi>;

  const counterAccount = Keypair.generate();

  it("Is initialized!", async () => {
    const transactionSignature = await cpiProgram.methods
      .initializeCpi()
      .accounts({
        counter: counterAccount.publicKey,
      })
      .signers([counterAccount])
      .rpc({ skipPreflight: true });

    const accountData = await program.account.counter.fetch(
      counterAccount.publicKey,
    );

    console.log(`Transaction Signature: ${transactionSignature}`);
    console.log(`Count: ${accountData.count}`);
  });

  it("Increment", async () => {
    const transactionSignature = await cpiProgram.methods
      .incrementCpi()
      .accounts({
        counter: counterAccount.publicKey,
      })
      .rpc();

    const accountData = await program.account.counter.fetch(
      counterAccount.publicKey,
    );

    console.log(`Transaction Signature: ${transactionSignature}`);
    console.log(`Count: ${accountData.count}`);
  });
});
```

</Tabs>

#### Explanation

<Steps>

<Step>

The `declare_program!()` macro takes a single argument - the name of the
program's IDL file (e.g. `example.json`):

```rust
declare_program!(example);  // Looks for /idls/example.json
```

</Step>

<Step>

Bring into scope the generated modules:

```rust
use example::{
    accounts::Counter, // Account types
    cpi::{             // Cross program invocation helpers
        self,
        accounts::{Increment, Initialize},
    },
    program::Example,  // Program type
};
```

</Step>

<Step>

Use the imported types in the account validation structs:

```rust
#[derive(Accounts)]
pub struct IncrementCpi<'info> {
    // Counter type from accounts module
    #[account(mut)]
    // [!code word:Counter]
    // [!code highlight]
    pub counter: Account<'info, Counter>,

    // Example type from program module
    // [!code word:Example]
    // [!code highlight]
    pub example_program: Program<'info, Example>,
}
```

</Step>

<Step>

Use the CPI module to invoke the program's instructions:

```rust
pub fn initialize_cpi(ctx: Context<InitializeCpi>) -> Result<()> {
    // Create CPI context for initialize
    let cpi_ctx = CpiContext::new(
        ctx.accounts.example_program.to_account_info(),
        Initialize {
            payer: ctx.accounts.payer.to_account_info(),
            counter: ctx.accounts.counter.to_account_info(),
            system_program: ctx.accounts.system_program.to_account_info(),
        },
    );

    // Invoke the initialize instruction
    // [!code highlight]
    cpi::initialize(cpi_ctx)?;
    Ok(())
}
```

```rust
pub fn increment_cpi(ctx: Context<IncrementCpi>) -> Result<()> {
    // Create CPI context for increment
    let cpi_ctx = CpiContext::new(
        ctx.accounts.example_program.to_account_info(),
        Increment {
            counter: ctx.accounts.counter.to_account_info(),
        },
    );

    // Invoke the increment instruction
    // [!code highlight]
    cpi::increment(cpi_ctx)?;
    Ok(())
}
```

</Step>

</Steps>

### Off-chain Client

To use the `declare_program!()` macro, you need the IDL file for the target
program. The IDL file must be placed in a directory named `/idls` in your
project. The `/idls` directory can be located at any level in your project
structure. For example, your project could have this layout:

<Files>
  <Folder name="idls" defaultOpen={true}>
    <File name="example.json" />
  </Folder>
  <Folder name="src" defaultOpen={true}>
    <File name="main.rs" />
  </Folder>
  <File name="Cargo.toml" />
</Files>

Below is the source code (`lib.rs`) for the target program that generates the
`example.json` IDL file shown above. The program's IDL can then be used in a
client script along with the `declare_program!()` macro to generate a Client
module to build the program's instructions.

<Tabs items={["Callee Program", "IDL"]}>

```rust tab="Callee Program"
use anchor_lang::prelude::*;

declare_id!("6khKp4BeJpCjBY1Eh39ybiqbfRnrn2UzWeUARjQLXYRC");

#[program]
pub mod example {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let counter = &ctx.accounts.counter;
        msg!("Counter account created! Current count: {}", counter.count);
        Ok(())
    }

    pub fn increment(ctx: Context<Increment>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        msg!("Previous counter: {}", counter.count);

        counter.count += 1;
        msg!("Counter incremented! Current count: {}", counter.count);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(mut)]
    pub payer: Signer<'info>,

    #[account(
        init,
        payer = payer,
        space = 8 + 8
    )]
    pub counter: Account<'info, Counter>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut)]
    pub counter: Account<'info, Counter>,
}

#[account]
pub struct Counter {
    pub count: u64,
}
```

```ts tab="IDL"
{
  "address": "6khKp4BeJpCjBY1Eh39ybiqbfRnrn2UzWeUARjQLXYRC",
  "metadata": {
    "name": "example",
    "version": "0.1.0",
    "spec": "0.1.0",
    "description": "Created with Anchor"
  },
  "instructions": [
    {
      "name": "increment",
      "discriminator": [11, 18, 104, 9, 104, 174, 59, 33],
      "accounts": [
        {
          "name": "counter",
          "writable": true
        }
      ],
      "args": []
    },
    {
      "name": "initialize",
      "discriminator": [175, 175, 109, 31, 13, 152, 155, 237],
      "accounts": [
        {
          "name": "payer",
          "writable": true,
          "signer": true
        },
        {
          "name": "counter",
          "writable": true,
          "signer": true
        },
        {
          "name": "system_program",
          "address": "11111111111111111111111111111111"
        }
      ],
      "args": []
    }
  ],
  "accounts": [
    {
      "name": "Counter",
      "discriminator": [255, 176, 4, 245, 188, 253, 124, 25]
    }
  ],
  "types": [
    {
      "name": "Counter",
      "type": {
        "kind": "struct",
        "fields": [
          {
            "name": "count",
            "type": "u64"
          }
        ]
      }
    }
  ]
}
```

</Tabs>

Below is the client script (main.rs) that uses the `declare_program!()` macro to
generate a Client module to build the program's instructions.

<Tabs items={["Client Script", "Dependencies"]}>

```rust tab="Client Script"
use anchor_client::{
    solana_client::rpc_client::RpcClient,
    solana_sdk::{
        commitment_config::CommitmentConfig, native_token::LAMPORTS_PER_SOL, signature::Keypair,
        signer::Signer, system_program,
    },
    Client, Cluster,
};
use anchor_lang::prelude::*;
use std::rc::Rc;

declare_program!(example);
use example::{accounts::Counter, client::accounts, client::args};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let connection = RpcClient::new_with_commitment(
        "http://127.0.0.1:8899", // Local validator URL
        CommitmentConfig::confirmed(),
    );

    // Generate Keypairs and request airdrop
    let payer = Keypair::new();
    let counter = Keypair::new();
    println!("Generated Keypairs:");
    println!("   Payer: {}", payer.pubkey());
    println!("   Counter: {}", counter.pubkey());

    println!("\nRequesting 1 SOL airdrop to payer");
    let airdrop_signature = connection.request_airdrop(&payer.pubkey(), LAMPORTS_PER_SOL)?;

    // Wait for airdrop confirmation
    while !connection.confirm_transaction(&airdrop_signature)? {
        std::thread::sleep(std::time::Duration::from_millis(100));
    }
    println!("   Airdrop confirmed!");

    // Create program client
    let provider = Client::new_with_options(
        Cluster::Localnet,
        Rc::new(payer),
        CommitmentConfig::confirmed(),
    );
    let program = provider.program(example::ID)?;

    // Build and send instructions
    println!("\nSend transaction with initialize and increment instructions");
    let initialize_ix = program
        .request()
        .accounts(accounts::Initialize {
            counter: counter.pubkey(),
            payer: program.payer(),
            system_program: system_program::ID,
        })
        .args(args::Initialize)
        .instructions()?
        .remove(0);

    let increment_ix = program
        .request()
        .accounts(accounts::Increment {
            counter: counter.pubkey(),
        })
        .args(args::Increment)
        .instructions()?
        .remove(0);

    let signature = program
        .request()
        .instruction(initialize_ix)
        .instruction(increment_ix)
        .signer(&counter)
        .send()
        .await?;
    println!("   Transaction confirmed: {}", signature);

    println!("\nFetch counter account data");
    let counter_account: Counter = program.account::<Counter>(counter.pubkey()).await?;
    println!("   Counter value: {}", counter_account.count);
    Ok(())
}
```

```toml tab="Dependencies"
[package]
name = "rs"
version = "0.1.0"
edition = "2021"

[dependencies]
anchor-client = { version = "0.31.1", features = ["async"] }
anchor-lang = "0.31.1"
anyhow = "1.0.93"
tokio = { version = "1.0", features = ["full"] }
```

</Tabs>

<Steps>

<Step>

The `declare_program!()` macro takes a single argument - the name of the
program's IDL file (e.g. `example.json`):

```rust
declare_program!(example);  // Looks for /idls/example.json
```

</Step>

<Step>

Bring into scope the generated modules:

```rust
use example::{
  accounts::Counter,  // Program Account types
  client::accounts,   // Accounts for program instructions
  client::args,       // Arguments for program instructions
};
```

</Step>

<Step>

Use the Client module to build the program's instructions:

```rust
// Build initialize instruction
let initialize_ix = program
    .request()
    // Accounts required for initialize instruction
    .accounts(accounts::Initialize {
        counter: counter.pubkey(),
        payer: program.payer(),
        system_program: system_program::ID,
    })
    // Arguments for initialize instruction (discriminator)
    .args(args::Initialize)
    .instructions()?
    .remove(0);
```

```rust
// Build increment instruction
let increment_ix = program
    .request()
    // Accounts required for increment instruction
    .accounts(accounts::Increment {
        counter: counter.pubkey(),
    })
    // Arguments for increment instruction (discriminator)
    .args(args::Increment)
    .instructions()?
    .remove(0);
```

</Step>
<Step>

Add the program's instructions to a transaction and send the transaction:

```rust
let signature = program
    .request()
    .instruction(initialize_ix)
    .instruction(increment_ix)
    .signer(&counter)
    .send()
    .await?;
```

</Step>

<Step>

Use the Account module to fetch and deserialize the program's account types:

```rust
// Counter type from accounts module
let counter_account: Counter = program.account::<Counter>(counter.pubkey()).await?;
```

</Step>

</Steps>
